﻿using System;
using System.Collections.Generic;
using UnityEditor.UIElements;
using UnityEngine;
using UnityEngine.UIElements;

namespace winS.UnityEditor.UIElement
{
    /// <summary>
    /// Provides support for creation and use of <see cref="EditorElement"/>.
    /// </summary>
    public static class EditorElementUtility
    {
        /// <summary>
        /// 文本内边距
        /// </summary>
        public static readonly float textPadding = 2f;
        /// <summary>
        /// 字段最小高度
        /// </summary>
        public static readonly float fieldMinHeight = 22f;
        /// <summary>
        /// 元素最小高度.
        /// <para>(从内部类 <see cref="UIElementsUtility"/>.singleLineHeight 中获取)</para>
        /// </summary>
        public static readonly float elementMinHeight = 18f;
        /// <summary>
        /// Default Vertical margin of <see cref="EditorControl"/>.
        /// </summary>
        public static readonly float defaultMarginVertical = 1f;
        /// <summary>
        /// Default horizontal margin of <see cref="EditorControl"/>.
        /// </summary>
        public static readonly float defaultMarginHorizontal = 2f;
        /// <summary>
        /// Default right margin of Label.
        /// </summary>
        public static readonly float defaultLabelMarginRight = 6f;

        public static readonly Color defaultFocusColor = ColorLevelUtility.GetColor(12);
        public static readonly Color defaultBorderColor = ColorLevelUtility.GetColor(4);
        public static readonly Color defaultSplitlineColor = ColorLevelUtility.GetColor(3);
        public static readonly Color defaultHighlightColor = new Color32(58, 121, 187, 255);
        public static readonly Color defaultSoftWhiteColor = new Color32(240, 240, 240, 255);

        public static readonly Color unitySoftWhiteColor = new Color32(196, 196, 196, 255);

        internal static readonly List<StylePropertyName> emptyPropertyList = new List<StylePropertyName>();
        internal static readonly List<StylePropertyName> topPropertyList = new List<StylePropertyName>() { "top" };
        internal static readonly List<StylePropertyName> leftPropertyList = new List<StylePropertyName>() { "left" };
        internal static readonly List<StylePropertyName> widthPropertyList = new List<StylePropertyName>() { "width" };
        internal static readonly List<StylePropertyName> heightPropertyList = new List<StylePropertyName>() { "height" };

        /// <summary>
        /// Default <see cref="ElementFactory"/>.
        /// </summary>
        public static readonly ElementFactory elementFactory = new ElementFactory();

        /// <summary>
        /// 将元素 <paramref name="content"/> 包装为非扩张性元素.
        /// 非扩张性元素只会报告指定宽度, 不会扩张父级
        /// </summary>
        public static Row CreateNonExpandRow(VisualElement content, float width, float flexGrow = 1f)
        {
            content.style.SetFlexBasis(width);
            content.style.flexGrow = flexGrow;
            return elementFactory.CreateRow(content, 0f);
        }
        public static Row AddPostfix(VisualElement content, string postfix)
        {
            Row row = elementFactory.CreateRow();
            content.style.flexGrow = 1f;
            row.Add(content);
            Label label = elementFactory.CreateLabel(postfix);
            label.style.marginLeft = label.style.marginRight = defaultMarginHorizontal;
            row.Add(label);
            return row;
        }
        public static Row MergeToRow(VisualElement visualElement1, VisualElement visualElement2, float rowFlexGrow = 0f)
        {
            Row row = elementFactory.CreateRow(rowFlexGrow);
            row.Add(visualElement1);
            row.Add(visualElement2);
            return row;
        }
        public static Row MergeToRow(VisualElement visualElement1, VisualElement visualElement2, VisualElement visualElement3, float rowFlexGrow = 0f)
        {
            Row row = MergeToRow(visualElement1, visualElement2, rowFlexGrow);
            row.Add(visualElement3);
            return row;
        }
        public static Row MergeToRow(VisualElement visualElement1, VisualElement visualElement2, VisualElement visualElement3, VisualElement visualElement4, float rowFlexGrow = 0f)
        {
            Row row = MergeToRow(visualElement1, visualElement2, visualElement3, rowFlexGrow);
            row.Add(visualElement4);
            return row;
        }
        public static Row MergeToRow(VisualElement visualElement1, float element1FlexGrow, VisualElement visualElement2, float element2FlexGrow, float rowFlexGrow = 0f)
        {
            Row row = elementFactory.CreateRow(rowFlexGrow);
            visualElement1.style.flexGrow = element1FlexGrow;
            visualElement2.style.flexGrow = element2FlexGrow;
            row.Add(visualElement1);
            row.Add(visualElement2);
            return row;
        }
        public static Row MergeToRow(VisualElement visualElement1, float element1FlexGrow, VisualElement visualElement2, float element2FlexGrow, VisualElement visualElement3, float element3FlexGrow, float rowFlexGrow = 0f)
        {
            Row row = MergeToRow(visualElement1, element1FlexGrow, visualElement2, element2FlexGrow, rowFlexGrow);
            visualElement3.style.flexGrow = element3FlexGrow;
            row.Add(visualElement3);
            return row;
        }
        public static Row MergeToRow(VisualElement visualElement1, float element1FlexGrow, VisualElement visualElement2, float element2FlexGrow, VisualElement visualElement3, float element3FlexGrow, VisualElement visualElement4, float element4FlexGrow, float rowFlexGrow = 0f)
        {
            Row row = MergeToRow(visualElement1, element1FlexGrow, visualElement2, element2FlexGrow, visualElement3, element3FlexGrow, rowFlexGrow);
            visualElement4.style.flexGrow = element4FlexGrow;
            row.Add(visualElement4);
            return row;
        }
        public static Row MergeToRow(VisualElement visualElement1, float element1FlexGrow, VisualElement visualElement2, float element2FlexGrow, VisualElement visualElement3, float element3FlexGrow, VisualElement visualElement4, float element4FlexGrow, VisualElement visualElement5, float element5FlexGrow, float rowFlexGrow = 0f)
        {
            Row row = MergeToRow(visualElement1, element1FlexGrow, visualElement2, element2FlexGrow, visualElement3, element3FlexGrow, visualElement4, element4FlexGrow, rowFlexGrow);
            visualElement5.style.flexGrow = element5FlexGrow;
            row.Add(visualElement5);
            return row;
        }
        public static Row MergeToRow(VisualElement visualElement1, float element1FlexGrow, VisualElement visualElement2, float element2FlexGrow, VisualElement visualElement3, float element3FlexGrow, VisualElement visualElement4, float element4FlexGrow, VisualElement visualElement5, float element5FlexGrow, VisualElement visualElement6, float element6FlexGrow, float rowFlexGrow = 0f)
        {
            Row row = MergeToRow(visualElement1, element1FlexGrow, visualElement2, element2FlexGrow, visualElement3, element3FlexGrow, visualElement4, element4FlexGrow, visualElement5, element5FlexGrow, rowFlexGrow);
            visualElement6.style.flexGrow = element6FlexGrow;
            row.Add(visualElement6);
            return row;
        }
        public static Row MergeToRowUsePercent(VisualElement visualElement1, float visualElement1WidthWeight, VisualElement visualElement2, float visualElement2WidthWeight, float rowFlexGrow = 0f)
        {
            float totalWidth = visualElement1WidthWeight + visualElement2WidthWeight;
            Row row = elementFactory.CreateRow(rowFlexGrow);
            visualElement1.style.SetWidth(visualElement1WidthWeight / totalWidth * 100f, LengthUnit.Percent);
            visualElement2.style.SetWidth(visualElement2WidthWeight / totalWidth * 100f, LengthUnit.Percent);
            row.Add(visualElement1);
            row.Add(visualElement2);
            return row;
        }
        public static Row MergeToRowUsePercent(VisualElement visualElement1, float visualElement1Width, VisualElement visualElement2, float visualElement2Width, VisualElement visualElement3, float visualElement3Width, float rowFlexGrow = 0f)
        {
            float totalWidth = visualElement1Width + visualElement2Width + visualElement3Width;
            Row row = elementFactory.CreateRow(rowFlexGrow);
            visualElement1.style.SetWidth(visualElement1Width / totalWidth * 100f, LengthUnit.Percent);
            visualElement2.style.SetWidth(visualElement2Width / totalWidth * 100f, LengthUnit.Percent);
            visualElement3.style.SetWidth(visualElement3Width / totalWidth * 100f, LengthUnit.Percent);
            row.Add(visualElement1);
            row.Add(visualElement2);
            row.Add(visualElement3);
            return row;
        }
        public static Row MergeToRowUsePercent(VisualElement visualElement1, float visualElement1Width, VisualElement visualElement2, float visualElement2Width, VisualElement visualElement3, float visualElement3Width, VisualElement visualElement4, float visualElement4Width, float rowFlexGrow = 0f)
        {
            float totalWidth = visualElement1Width + visualElement2Width + visualElement3Width + visualElement4Width;
            Row row = elementFactory.CreateRow(rowFlexGrow);
            visualElement1.style.SetWidth(visualElement1Width / totalWidth * 100f, LengthUnit.Percent);
            visualElement2.style.SetWidth(visualElement2Width / totalWidth * 100f, LengthUnit.Percent);
            visualElement3.style.SetWidth(visualElement3Width / totalWidth * 100f, LengthUnit.Percent);
            visualElement4.style.SetWidth(visualElement4Width / totalWidth * 100f, LengthUnit.Percent);
            row.Add(visualElement1);
            row.Add(visualElement2);
            row.Add(visualElement3);
            row.Add(visualElement4);
            return row;
        }
        public static Row MergeToRowUsePercent(VisualElement visualElement1, float visualElement1Width, VisualElement visualElement2, float visualElement2Width, VisualElement visualElement3, float visualElement3Width, VisualElement visualElement4, float visualElement4Width, VisualElement visualElement5, float visualElement5Width, float rowFlexGrow = 0f)
        {
            float totalWidth = visualElement1Width + visualElement2Width + visualElement3Width + visualElement4Width + visualElement5Width;
            Row row = elementFactory.CreateRow(rowFlexGrow);
            visualElement1.style.SetWidth(visualElement1Width / totalWidth * 100f, LengthUnit.Percent);
            visualElement2.style.SetWidth(visualElement2Width / totalWidth * 100f, LengthUnit.Percent);
            visualElement3.style.SetWidth(visualElement3Width / totalWidth * 100f, LengthUnit.Percent);
            visualElement4.style.SetWidth(visualElement4Width / totalWidth * 100f, LengthUnit.Percent);
            visualElement5.style.SetWidth(visualElement5Width / totalWidth * 100f, LengthUnit.Percent);
            row.Add(visualElement1);
            row.Add(visualElement2);
            row.Add(visualElement3);
            row.Add(visualElement4);
            row.Add(visualElement5);
            return row;
        }

        public static Column MergeToColumn(VisualElement visualElement1, VisualElement visualElement2, float columnFlexGrow = 0f)
        {
            Column column = elementFactory.CreateColumn(columnFlexGrow);
            column.Add(visualElement1);
            column.Add(visualElement2);
            return column;
        }
        public static Column MergeToColumn(VisualElement visualElement1, VisualElement visualElement2, VisualElement visualElement3, float columnFlexGrow = 0f)
        {
            Column column = MergeToColumn(visualElement1, visualElement2, columnFlexGrow);
            column.Add(visualElement3);
            return column;
        }
        public static Column MergeToColumn(VisualElement visualElement1, float element1FlexGrow, VisualElement visualElement2, float element2FlexGrow, float columnFlexGrow = 0f)
        {
            Column column = elementFactory.CreateColumn(columnFlexGrow);
            visualElement1.style.flexGrow = element1FlexGrow;
            visualElement2.style.flexGrow = element2FlexGrow;
            column.Add(visualElement1);
            column.Add(visualElement2);
            return column;
        }
        public static void ApplyFocusElementStyle(EditorElement focusElement, Color normalColor)
        {
            focusElement.RegisterCallback<MouseLeaveEvent>(_ => focusElement.style.SetBorderColor(normalColor));
            focusElement.RegisterCallback<MouseEnterEvent>(_ => focusElement.style.SetBorderColor(defaultFocusColor));
        }
        public static void RegisterClickEvent(VisualElement visualElement, Action clickCallback)
        {
            visualElement.RegisterCallback<ClickEvent>(clickEvent =>
            {
                clickCallback();
                clickEvent.StopPropagation();
            });
            visualElement.RegisterCallback<MouseDownEvent>(mouseDownEvent => mouseDownEvent.StopPropagation());
        }

        internal static void ApplySubFieldStyle(VisualElement visualElement)
        {
            if (visualElement is IEditorField editorField)
            {
                editorField.ApplySubFieldStyle();
                return;
            }
            visualElement.style.minHeight = StyleKeyword.Auto;
            visualElement.style.flexGrow = visualElement.style.flexShrink = 1f;
            visualElement.style.SetMargin(0f);
        }
    }
}